package Thread;

import java.util.PriorityQueue;

// 描述任务；注意，这个类要添加进优先级队列，需要能比较，所以要实现 Comparable 接口
class MyTimerTask implements Comparable<MyTimerTask>{

    // 我们在这里约定使用一个时间戳表示任务执行时间
    private long time;

    public long getTime() {
        return time;
    }

    private Runnable runnable;

    @Override
    public int compareTo(MyTimerTask o) {
        // 这里不用去记哪个减哪个是小根堆，直接写完测试一遍，不是就反过来
        return (int)(this.time - o.time);
    }

    public MyTimerTask(Runnable runnable, long delay) {
        this.runnable = runnable;
        // time的赋值是：获取当前时间 + delay  就能得到我们想要的效果：
        // 假设我们是13:00：00设置的，期望3s过后执行代码，那么time此时获取的时间就是 13:00:00 + 00:00:03 = 13:00:03
        // 那么达到 13:00:03后，就会执行代码
        this.time = System.currentTimeMillis() + delay;
    }

    public void run() {
        runnable.run();
    }



}

// 定时器：创建线程；添加任务；指定时间
class MyTimer {
    // 有一个线程
    private Thread t = null;

    // 有一个优先级队列
    // 这个优先级队列可以放在MyTimerTask里面吗？不行，因为这个类要用到这个队列，去添加任务
    private PriorityQueue<MyTimerTask> queue = new PriorityQueue();

    Object locker = new Object();


    public void schedule(Runnable runnable, long delay) {
        // 1.首先要有一个任务
        // 2.将任务添加到优先级队列中
        synchronized (locker) {
            MyTimerTask task = new MyTimerTask(runnable,delay);
            queue.offer(task);

            locker.notify();
        }
    }


    // 构造方法的任务就是：实例线程；不断判断堆顶元素；然后执行
    public MyTimer() {
        t = new Thread(() -> {
            // 时刻关注，所以先来一个 true 循环
            try {
                synchronized (locker) {
                    while (true) {
                        while (queue.isEmpty()) {
                            locker.wait();
                        }
                        // 如果队列不为空，则peek一下堆顶元素
                        // 再以当前时间与堆顶任务的设定时间相对比，
                        // 如果大于等于，则执行；若不大于，说明还没到时间
                        MyTimerTask task = queue.peek();
                        long curTime = System.currentTimeMillis();
                        if (curTime >= task.getTime()) {
                            queue.poll();
                            task.run();
                        }else {
                            locker.wait(task.getTime() - curTime);
                        }
                    }
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        //别忘了启动线程
        t.start();
    }

}

public class ThreadDemo24 {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();

        myTimer.schedule(() -> {
            System.out.println("time:3000");
        },3000);

        myTimer.schedule(() -> {
            System.out.println("time:2000");
        },2000);

        myTimer.schedule(() -> {
            System.out.println("time:1000");
        },1000);
    }
}
